home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1995 #5 & #6
/
Amiga Plus CD - 1995 - No. 5 and 6.iso
/
pd
/
netz
/
netinput
/
source
/
unixsem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-26
|
4KB
|
148 lines
/*
** $VER: unixsem.c 1.0 (05 Mar 95)
**
** UNIX like counting semaphores for the AMIGA
**
** (C) Copyright 1995 Marius Gröger
** All Rights Reserved
**
** $HISTORY:
**
** 05 Mar 1995 : 001.000 : created
*/
#ifndef CLIB_ALIB_PROTOS_H
#include <clib/alib_protos.h>
#endif
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_pragmas.h>
#endif
#include "unixsem.h"
/* private structure to maintain tasks within the waiting space of a semaphore */
struct semachain
{
struct MinNode link; /* std exec minimal node */
struct Task *this; /* the task waiting to get granted a semaphore unit */
ULONG sigmask; /* the task waits for this exec signal */
};
/* Initialize a semaphore for use. This sets various private fields.
The user may provide an Exec style signal-mask which should be used
for waiting operertions concerning THIS semaphore. If signal is
equal to -1, the default signal-mask UNIXSEM_SIGMASK is used. This
is defined in "unixsem.h" and may be altered with succeeding recompilation
of ALL modules using the semaphore calls.
The unit counter is set to zero.
*/
extern VOID
sinit(
CountSemaphore *sem /* pointer to a semaphore */,
ULONG sigmask /* exec signal-mask to be used for waiting
operations or -1 to used UNIXSEM_SIGMASK */
)
{
InitSemaphore(&sem->sem_Lock);
NewList((struct List*)&sem->sem_WaitingSpace);
sem->sem_Count = 0;
sem->sem_SigMask = (sigmask != (ULONG)(-1)) ? sigmask : UNIXSEM_SIGMASK;
}
/* Set a semaphore to a certain value. This is done independent of
any task possibly waiting fo the semaphore. Therefore this function
should only be called prior to any call of ssignal() or swait().
To create a mutual exclusion semaphore for protected areas of code,
te following sequence is appropriate:
sinit(&mutex,-1);
sset(&mutex,1);
Anybody who wants to enter the protected area later should
perform these steps:
swait(&mutex);
// protected area here
ssignal(&mutex);
This has, of course, the same result as an according ObainSemaphore()/
ReleaseSemaphore() construct, but might be useful when porting UNIX
applications.
*/
extern VOID sset(
CountSemaphore *sem /* pointer to a semaphore */,
LONG val /* value the semaphore should be assigned */
)
{
/* always single-threaden the semaphore access */
ObtainSemaphore(&sem->sem_Lock);
sem->sem_Count = val;
ReleaseSemaphore(&sem->sem_Lock);
}
/* Increment the unit counter of a semaphore. If there are any tasks waiting
for a unit, the chronologically first waiter will be awakened.
*/
extern VOID ssignal(
CountSemaphore *sem /* pointer to a semaphore */
)
{
struct semachain *sc;
/* always single-threaden the semaphore access */
ObtainSemaphore(&sem->sem_Lock);
/* add a unit, have to wake up somebody ? */
if (sem->sem_Count++ < 0)
{
/* there MUST be at least one waiter! */
sc = (struct semachain*)RemHead((struct List*)&sem->sem_WaitingSpace);
Signal(sc->this, sc->sigmask);
}
ReleaseSemaphore(&sem->sem_Lock);
}
/* Decrement the unit count of a semaphore. If the unit count before the
call to swait() was less or equal to zero, the task will be added
to the semaphore's waiting space and fall asleep until sombody
calls ssignal() to the semaphore. If there are already other tasks
within the waiting space, these will be waked up first, before your
task is.
*/
extern VOID swait(
CountSemaphore *sem /* pointer to a semaphore */
)
{
struct semachain sc;
BOOL sleep;
ObtainSemaphore(&sem->sem_Lock);
/* get a unit, go to sleep ? */
if (--sem->sem_Count < 0)
{
/* delay the Wait() till after ReleaseSemaphore() */
sleep = TRUE;
sc.sigmask = sem->sem_SigMask;
sc.this = FindTask(NULL);
AddTail((struct List*)&sem->sem_WaitingSpace, (struct Node*)&sc.link);
}
else
{
sleep = FALSE;
}
ReleaseSemaphore(&sem->sem_Lock);
/*
** Note: maybe we are now de-queued again by a concurrent ssignal()
** and got the exec-signal before we Wait() for it. This is ok.
** Fortunatly, it is not possible for us to have more than
** one semachain pending, as this would be a bit trickier to
** handle (exec signals do not nest).
*/
if (sleep) Wait(sem->sem_SigMask);
}